package com.zhongfl.crm.lixiao.batch.service;

import com.heptagram.lixiao.api.LiXiaoService;
import com.heptagram.lixiao.bean.request.revisitlog.LXRevisitLogListRequest;
import com.heptagram.lixiao.bean.response.LXUserResponse;
import com.heptagram.lixiao.bean.response.revisitlog.LXRevisitLogResponse;
import com.heptagram.lixiao.common.exception.LiXiaoErrorException;
import com.zhongfl.crm.enums.boss.MessageSendType;
import com.zhongfl.crm.enums.boss.OrderAttachmentType;
import com.zhongfl.crm.lixiao.config.MailConfigInfo;
import com.zhongfl.crm.lixiao.mapper.LXOrderMapper;
import com.zhongfl.crm.mail.MailService;
import com.zhongfl.crm.mail.bean.MailMessage;
import com.zhongfl.crm.mail.bean.MailMessageBuilder;
import com.zhongfl.crm.mail.enums.MailTypeEnum;
import com.zhongfl.crm.model.LxUser;
import com.zhongfl.crm.model.boss.*;
import com.zhongfl.crm.service.LxUserService;
import com.zhongfl.crm.service.boss.AttachmentService;
import com.zhongfl.crm.service.boss.LXOrderService;
import com.zhongfl.crm.service.boss.MessageSendTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * LXRevisitLogService 抽象类
 *
 * @author tiantian
 * @date 2018/7/12 13:52
 */
@Slf4j
public abstract class LXRevisitLogService {
    @Resource
    private LiXiaoService liXiaoService;
    @Resource
    private MailConfigInfo mailConfigInfo;
    @Resource
    private MailService mailService;
    @Resource
    private AttachmentService attachmentService;
    @Resource
    private LXOrderMapper lxOrderMapper;
    @Resource
    private LXOrderService lxOrderService;
    @Resource
    private MessageSendTaskService messageSendTaskService;
    @Resource
    private LxUserService lxUserService;

    public final void syncRevisitLog(String loggableType, boolean isInitData) throws LiXiaoErrorException, InterruptedException {
        LXRevisitLogListRequest request = new LXRevisitLogListRequest();
        //opportunity | contract | lead | customer
        request.setLoggableType(loggableType);
        if (!isInitData) {
            //时间范围没起作用？还是查全部
            String startDate = LocalDate.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            String endDate = LocalDate.now().plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            request.setStartDate(startDate);
            request.setEndDate(endDate);
        }
        request.setPageIndex(1);
        request.setPageSize(100);

        List<Map<String, Object>> syncErrorList = new ArrayList<>();

        LXRevisitLogResponse result;
        do {
            result = liXiaoService.getRevisitLogService().findRevisitLogs(request);
            if (Objects.isNull(result)) {
                log.info("没有查询到最新的跟进记录");
                return;
            }
            if (result.getData().getTotalCount() == 0) {
                log.info("没有查询到最新的跟进记录");
                return;
            }

            this.syncRevisitLogList2Boss(loggableType, result, syncErrorList);

            request.setPageIndex(request.getPageIndex() + 1);
            Thread.sleep(2000);
        } while (result.getData().hasNextPage());

        this.sendNotifyMail(syncErrorList);
    }

    abstract void syncRevisitLogList2Boss(String loggableType, LXRevisitLogResponse result, List<Map<String, Object>> syncErrorList);

    public <T> void syncSingleRecord2Boss(LXRevisitLogResponse.RevisitLog revisitLog, T obj, List<Map<String, Object>> syncErrorList) {
        this.syncRemark(revisitLog, obj);
        this.syncComments(revisitLog, obj, syncErrorList);
    }

    abstract <T> void syncRemark(LXRevisitLogResponse.RevisitLog revisitLog, T obj);

    abstract <T> void syncComments(LXRevisitLogResponse.RevisitLog revisitLog, T obj, List<Map<String, Object>> syncErrorList);

    public void syncFiles(LXRevisitLogResponse.RevisitLog revisitLog, OrderMemorandum orderMemorandum) {
        if (!CollectionUtils.isEmpty(revisitLog.getImageAttachments())) {
            this.uploadImages(revisitLog.getImageAttachments(), orderMemorandum);
        }
        // todo 文件的后缀要得到上传的文件才能确定
        //if(!CollectionUtils.isEmpty(revisitLog.getAttachmentFiles())){
        //    this.uploadImages(revisitLog.getAttachmentFiles(),orderMemorandum);
        //}
    }

    private void uploadImages(List<LXRevisitLogResponse.Attachment> files, OrderMemorandum orderMemorandum) {
        files.forEach(item -> {
            String fileName = attachmentService.uploadLxFileInputStream2OSS(item.getPublicUrl());
            attachmentService.save(fileName, orderMemorandum.getOrderNo(), orderMemorandum.getId().toString(), OrderAttachmentType.ORDER_MEMORANDUM_FILE.toString(), orderMemorandum.getStaffName());
        });
    }

    /**
     * 收集错误信息
     */
    public void collectErrorMessage(Exception ex, List<Map<String, Object>> syncErrorList, LXRevisitLogResponse.RevisitLog revisitLog) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("obj", revisitLog);
        map.put("msg", "跟进: " + ex.getMessage());
        syncErrorList.add(map);
    }

    /**
     * 发送错误邮件
     */
    public void sendNotifyMail(List<Map<String, Object>> syncErrorList) {
        try {
            if (syncErrorList.isEmpty()) {
                return;
            }

            MailMessage mailMessage = MailMessageBuilder.builder()
                    .mailTypeEnum(MailTypeEnum.LX_REVISIT_LOG_SYNC_ERROR)
                    .subject("励销跟进记录同步异常通知-" + mailConfigInfo.getActiveProfiles())
                    .to(mailConfigInfo.getDefaultTo())
                    .addData("title", "BOSS  励销跟进记录同步异常通知")
                    .addData("syncErrorList", syncErrorList)
                    .build();

            mailService.send(mailMessage);

        } catch (Exception ex) {
            log.error("发送邮件异常: {}", ex.getMessage(), ex);
        }
    }

    /**
     * CRM添加-订单跟进记录通知
     * 1.获取当前跟进记录的订单信息
     * 1.1方案一：从boss获取，减少调用一次接口，但协作人的信息是否准确
     * 1.2方案二：从CRM获取，不仅调用订单接口，还要调用协作人接口。
     * 1.3解决方案：从boss获取，以boss信息为准。
     * 2.从订单获取订单和协作人信息，商务和交付经理信息。
     * 3.将atUsers添加进来。
     * 4.去重并去掉当前操作人
     */
    public void addOrderRevisitLogNotify(LXRevisitLogResponse.RevisitLog revisitLog) {
        if (Objects.isNull(revisitLog)) {
            return;
        }

        LxOrder lxOrder = this.getLXOrder(revisitLog);
        if (Objects.isNull(lxOrder)) {
            return;
        }

        Order order = lxOrderService.findByOrderNo(lxOrder.getOrderNo());
        if (Objects.isNull(order)) {
            return;
        }

        LxUser user = lxUserService.findByLxId(revisitLog.getUser().getId());
        if (Objects.isNull(user)) {
            return;
        }

        List<String> staffs = new ArrayList<>();
        List<LXRevisitLogResponse.AtUser> atUsers = revisitLog.getAtUsers();
        if (atUsers.size() > 0) {
            atUsers.forEach(item -> {
                LxUser lxUser = lxUserService.findByLxId(item.getUserId());
                if (Objects.nonNull(lxUser) && StringUtils.isNotEmpty(lxUser.getStaffCode())) {
                    staffs.add(lxUser.getStaffCode());
                }
            });
        }

        OrderRevisitLogChangeMessage messageBody = OrderRevisitLogChangeMessage.builder()
                .orderNo(order.getOrderNo())
                .loanUserName(order.getName())
                .operStaffCode(user.getStaffCode())
                .operStaffName(user.getStaffName())
                .atUsers(staffs)
                .build();

        messageSendTaskService.save(MessageSendType.ORDER_REVISIT_LOG_CHANGE_MSG,
                lxOrder.getOrderNo(),
                UUID.randomUUID().toString(),
                TopicConsts.ORDER_REVISIT_LOG_CHANGE,
                messageBody);
    }

    private LxOrder getLXOrder(LXRevisitLogResponse.RevisitLog revisitLog){
        LxOrder lxOrder = null;
        switch (revisitLog.getLoggableType()) {
            case "Opportunity":
                lxOrder = lxOrderMapper.selectByLXId(revisitLog.getLoggableId());
                break;
            case "Contract":
                lxOrder = lxOrderMapper.selectByContractId(revisitLog.getLoggableId());
                break;
            default:
                break;
        }
        return lxOrder;
    }

    /**
     * CRM添加订单跟进记录评论通知
     */
    public void addOrderRevisitLogCommentNotify(LXRevisitLogResponse.RevisitLog revisitLog, LXRevisitLogResponse.Comment comment) {
        if (Objects.isNull(revisitLog) || Objects.isNull(comment)) {
            return;
        }

        LxOrder lxOrder = this.getLXOrder(revisitLog);
        if (Objects.isNull(lxOrder)) {
            return;
        }

        Order order = lxOrderService.findByOrderNo(lxOrder.getOrderNo());
        if (Objects.isNull(order)) {
            return;
        }

        LxUser user = lxUserService.findByLxId(comment.getUser().getId());
        if (Objects.isNull(user)) {
            return;
        }

        String replyToUserStaffCode = null;
        LXUserResponse.User replyToUser = comment.getReplyToUser();
        if(Objects.nonNull(replyToUser)){
            LxUser lxUser = lxUserService.findByLxId(replyToUser.getId());
            if(StringUtils.isNotEmpty(lxUser.getStaffCode())){
                replyToUserStaffCode = lxUser.getStaffCode();
            }
        }

        OrderRevisitLogChangeMessage messageBody = OrderRevisitLogChangeMessage.builder()
                .orderNo(order.getOrderNo())
                .loanUserName(order.getName())
                .operStaffCode(user.getStaffCode())
                .operStaffName(user.getStaffName())
                .replyToUser(replyToUserStaffCode)
                .build();

        messageSendTaskService.save(MessageSendType.ORDER_REVISIT_LOG_COMMENT_CHANGE_MSG,
                lxOrder.getOrderNo(),
                UUID.randomUUID().toString(),
                TopicConsts.ORDER_REVISIT_LOG_COMMENT_CHANGE,
                messageBody);
    }

    /**
     * CRM跟进记录-通知谁看-消息发送
     * 将此通知合并到放在跟进记录新增里
     */
    @Deprecated
    public void atUsersNotify() {

    }

    /**
     * CRM删除订单跟进记录通知
     * todo 跟进记录属于一次性消费的信息，删除的通知并不重要，删除的记录应该在同步的时候判断是否删除，目前不知道怎么做。
     */
    @Deprecated
    public void deleteOrderRevisitLogNotify() {

    }

    /**
     * CRM删除订单跟进记录-评论通知
     * todo 同上
     */
    @Deprecated
    public void deleteOrderRevisitLogCommentNotify() {

    }

}
